package chap10

abstract class Element {
  def contents : Array[String]
  
  def justify : Justify
  
  def width: Int = contents(0).length
  def height: Int = contents.length
  
  def above(that: Element): Element = {
    val widendThis = this widen that.width
    val widendThat = that widen this.width
    Element(widendThis.contents ++ widendThat.contents, justify)
  }
  
  def beside(that: Element): Element = {
    val heightendThis = this heighten that.height
    val heightendThat = that heighten this.height
    Element(
    	for((lineThis,lineThat) <- heightendThis.contents zip heightendThat.contents)
    	  yield lineThis + lineThat,
    	justify
    )
  }
  
  def widen(w: Int): Element = {
    if(w <= width) {
      this
    } else {
      /*val left = Element(' ', (w - width) / 2, height)
      val right = Element(' ', w - width - left.width, height)
      left beside this beside right*/
      justify.justify(this, w)
    }
  }
  
  def heighten(h: Int): Element = {
    if(h <= height) {
      this
    } else {
      val top = Element(' ', width, (h - height) / 2, justify)
      val bot = Element(' ', width, h - height - top.height, justify)
      top above this above bot
    }
  }
  
  override def toString = contents mkString "\n"
}

object Element {
  
  private class ArrayElement (
    val contents : Array[String],
    val justify : Justify) extends Element
    
  private class LineElement(str : String,
      val justify : Justify) extends Element {
    val contents = Array(str)
    override def width = str.length
    override def height = 1
  }
  
  private class UniformElement(ch: Char,
      override val width: Int,
      override val height: Int,
      val justify : Justify) extends Element {
    private val line = ch.toString *  width
    def contents = Array.fill(height)(line)
  }
  
  def apply(contents: Array[String]): Element = {
    new ArrayElement(contents, Justify("center"))
  }
  
  def apply(contents: Array[String], justify : Justify): Element = {
    new ArrayElement(contents, justify)
  }
  
  def apply(ch: Char, width: Int, height: Int): Element = {
    new UniformElement(ch, width, height, Justify("center"))
  }
  
  def apply(ch: Char, width: Int, height: Int, justify : Justify): Element = {
    new UniformElement(ch, width, height, justify)
  }
  
  def apply(line: String): Element = {
    new LineElement(line, Justify("center"))
  }
  
  def apply(line: String, justify: Justify): Element = {
	  new LineElement(line, justify) 
  }
}